-desired survivor size: 期望的Survivor大小。该值等于Survivor大小乘以TargetSurvivorRatio (默认50%)。
target threshold:目标阈值。表示一个对象的年龄,这个值可以通过每个年龄的所有对象大小相加直到大于desired survivor size计算出来。
age distribution: 年龄分布。包括了每个年龄所有对象的大小以及增量Survivor区大小
最近在看关于G1垃圾收集的文章,看了很多国内与国外的资料,本文对G1的这些资料进行了整理。这篇合适JVM垃圾回收有一定基础的同学,作为G1入门可以看一下。
Card Table
和Remember Set
的概念,基本思想就是用空间换时间。这两个数据结构是专门用来处理Old区到Young区的引用。Young区到Old区的引用则不需要单独处理,因为Young区中的对象本身变化比较大,没必要浪费空间去记录下来。RSet:全称Remembered Sets, 用来记录外部指向本Region的所有引用,每个Region维护一个RSet。
Card: JVM将内存划分成了固定大小的Card。这里可以类比物理内存上page的概念。
RSet
与Card
的关系。每个Region
被分成了多个Card
,其中绿色部分的Card
表示该Card
中有对象引用了其他Card
中的对象,这种引用关系用蓝色实线表示。RSet
其实是一个HashTable,Key是Region的起始地址,Value是Card Table
(字节数组),字节数组下标表示Card
的空间地址,当该地址空间被引用的时候会被标记为dirty_card
。黑色:根对象,或者该对象与它的子对象都被扫描
灰色:对象本身被扫描,但还没扫描完该对象中的子对象
白色:未被扫描对象,扫描完成所有对象之后,最终为白色的为不可达对象,即垃圾对象。
A.c=C
B.c=null
pre-write barrier
解决这个问题。简单说就是在并发标记阶段,当引用关系发生变化的时候,通过pre-write barrier
函数会把这种这种变化记录并保存在一个队列里,在JVM源码中这个队列叫satb_mark_queue
。在remark阶段会扫描这个队列,通过这种方式,旧的引用所指向的对象就会被标记上,其子孙也会被递归标记上,这样就不会漏标记任何对象,snapshot的完整性也就得到了保证。-XX:MaxGCPauseMillis
,用来指定一个G1收集过程目标停顿时间,默认值200ms,当然这只是一个期望值。G1的强大之处在于他有一个停顿预测模型(Pause Prediction Model),他会有选择的挑选部分Region,去尽量满足停顿时间,关于G1的这个模型是如何建立的,这里不做深究。XX:InitiatingHeapOccupancyPercent
表示老年代占整个堆大小的百分比,默认值是45%,达到该阈值就会触发一次Mixed GC。初始标记(initial mark,STW)。它标记了从GC Root开始直接可达的对象。初始标记阶段借用young GC的暂停,因而没有额外的、单独的暂停阶段。
并发标记(Concurrent Marking)。这个阶段从GC Root开始对heap中的对象标记,标记线程与应用程序线程并行执行,并且收集各个Region的存活对象信息。过程中还会扫描上文中提到的SATB write barrier所记录下的引用。
最终标记(Remark,STW)。标记那些在并发标记阶段发生变化的对象,将被回收。
清除垃圾(Cleanup,部分STW)。这个阶段如果发现完全没有活对象的region就会将其整体回收到可分配region列表中。清除空Region。
Evacuation的时候没有足够的to-space来存放晋升的对象;
并发处理过程完成之前空间耗尽
-XX:+PrintGCDetails
参数查看的Young GC日志如下:2016-12-12T10:40:18.811-0500:GC发生的时间(通过设置-XX:+PrintGCDateStamps
打印)
29.959:相对JVM启动的时间
G1 Evacuation Pause (young):GC类型,表示这是evacuation停顿,并且是Young GC。
0.0305171 sec:本次GC耗时。
Parallel Time:26.6 。并行任务花费的STW的时间,从收集开始到最后一个GC线程结束。
GC Workers:4 。并行收集的线程数量。通过 -XX:ParallelGCThreads。当CPU数量小于8时,该值为CPU个数,最大设置成8,对于多于8个的CPU,将默认取CPU个数的5/8。
GC Worker start:最小|最大时间戳表示第一个线程和最后一个线程的启动时间。理想情况下希望同时启动。
**Ext Root Scanning **:扫描外部根节点的时间。外部节点包括JNI、全局变量、线程栈等。
**Update RS (Remembered Set or RSet) **:每个线程更新RSet的时间。
**Scan RS **: 扫描每个CSet中Region的RSet,避免了扫描整个老年代。
Code Root Scanning:扫描code root耗时。Code Root是JIT编译后的代码里引用了heap中的对象。
Object Copy:拷贝存活对象到新的Region.
Termination: 当GC线程完成任务之后尝试结束到真正结束耗时。因为在结束前他会检查其他线程是否有未完成的任务,帮助完成之后再结束。
GC Worker Other:线程花费在其他工作上的时间
GC Worker Total:每个线程花费的时间总和。
GC Worker End: 每个线程的结束时间。最小|最大时间戳表示第一个线程和最后一个线程的结束时间。理想情况下希望同时结束。
Code Root Fixup:修复GC期间code root指针改变的耗时
Code Root Purge:清除code root耗时
Clear CT:清除card tables 中的dirty card的耗时
Eden: 1097.0M(1097.0M)->0.0B(967.0M):表明了Young GC被触发,因为Eden区已经满了(分配了1097M 已经使用了1097.0M),并且Eden区都被清空了(0B),下次垃圾回收Eden区大小降到967M。
Survivors: 13.0M->139.0M:Young GC之后,Survivor从13M增加到了139M
Heap: 1694.4M(2048.0M)->736.3M(2048.0M):开始前整个堆占用了1694.4M,最大可分配2048M,在收集之后,整个堆占用736M,最大可分配没有变还是2048M。
user=0.08:在垃圾回收时,花费在用户代码上的CPU时间。这个时间包含了所有线程运行的CPU时间,所以比real-time大很多
sys=0.00: 花费在系统内核上的时间。
real=0.03: 垃圾回收的实际时间。这里包括了其他进程的时间和等待时间。
GC pause (G1 Evacuation Pause) (young) (initial-mark):利用STW停顿期间,跟踪所有可达对象,该阶段和Young GC一起执行。同时该阶段也设置两个指针TAMS来标识已经存在的对象以及在并发标记阶段新生成的对象。
② 第一个并发事件
GC concurrent-root-region-scan-start: 扫描初始化标记阶段Survivor区的root Region并标记出来。
GC concurrent-mark-start:该阶段和应用线程一起执行,并发线程数默认是并行线程数的四分之一。可以通过-XX:ConcGCThreads
显示指定。
GC remark / Finalize Marking / GC ref-proc / Unloading: 这个阶段
GC concurrent-cleanup-start:处理第5阶段所有空的Region。每个Region中的RSet被清空,当所有的Region都被清理完成,他们会被加入到一个临时表中,最终会被合并到master free list。
-XX:+PrintAdaptiveSizePolicy
和-XX:+PrintTenuringDistribution
两个标签,可以帮助大家更好的分析日志。-XX:+PrintAdaptiveSizePolicy
: 显示收集器工效(Collector ergonomics)
-XX:+PrintTenuringDistribution
: Survivor区的使用和分布
-XX:+PrintAdaptiveSizePolicy
之后的日志如下:-XX:+PrintAdaptiveSizePolicy
之后执行日志-XX:G1OldCSetRegionThresholdPercent=X
可以更改-XX:+PrintAdaptiveSizePolicy
之后执行日志-XX:InitiatingHeapOccupancyPercent
(IHOP)调节,这个参数设置使用整个对的x%时,系统开始进行并行GC。注意是整个堆的百分比。-XX:+PrintTenuringDistribution
: 可以查看每次回收期间,Survivor区的分布信息。可以帮助我们查看对象年龄的变化。target threshold:目标阈值。表示一个对象的年龄,这个值可以通过每个年龄的所有对象大小相加直到大于desired survivor size计算出来。
age distribution: 年龄分布。包括了每个年龄所有对象的大小以及增量Survivor区大小
文章不错?点个【在看】吧! 👇